package com.faxsun.core.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.faxsun.core.persist.entity.PostPO;
import com.faxsun.core.persist.entity.TagPO;
import com.faxsun.core.pojos.enums.PostType;
import com.faxsun.core.pojos.enums.TagType;
import com.faxsun.core.service.AggregationService;
import com.faxsun.pojos.TagAggregation;

import mblog.core.persist.dao.PostDao;
import mblog.core.persist.dao.TagDao;
import mblog.core.pojos.Post;
import mblog.core.pojos.Tag;
import mblog.core.utils.BeanMapUtils;
import mtons.modules.pojos.Page;

/**
 * 根据tag聚合相关内容
 * @author songdragon 2015年5月11日
 *
 */
public class AggregationServiceImpl implements AggregationService {
	private static final Logger LOG = LoggerFactory
			.getLogger(AggregationServiceImpl.class);

	@Autowired
	private PostDao postDao;
	
	@Autowired
	private TagDao tagDao;
    
    private final static String CACHE = "aggregationServiceCache";

	@Override
	@Transactional(readOnly = true)
	public TagAggregation aggregateProduct(Page page, Tag productTag) {
		TagAggregation aggregation = null;
		if (productTag == null || StringUtils.isEmpty(productTag.getName())
				|| productTag.getType() != TagType.PRODUCT) {
			aggregation = null;
		} else {
			List<Tag> tags = new ArrayList<Tag>();
			tags.add(productTag);
			aggregation = aggregateByMultipleTags(page, tags);
		}
		return aggregation;
	}

	@Override
	@Transactional(readOnly = true)
	public TagAggregation aggregateCategory(Page page, Tag categoryTag) {
		TagAggregation aggregation = null;
		if (categoryTag == null || StringUtils.isEmpty(categoryTag.getName())) {
			aggregation = null;
		} else {
			List<Tag> tags = new ArrayList<Tag>();
			tags.add(categoryTag);
			aggregation = aggregateByMultipleTags(page, tags);
		}
		return aggregation;
	}

	@Override
	@Transactional(readOnly = true)
    @Cacheable(value = CACHE, key = "'aggregateEvulationsByTag?pageNo'+#page.pageNo+'&maxResults='+#page.maxResults+'&tagId='+#tag.id")
	public TagAggregation aggregateEvulationsByTag(Page page, Tag tag) {
		TagAggregation aggregation = null;
		if (tag == null || StringUtils.isEmpty(tag.getName())) {
			aggregation = null;
		} else {
			List<Tag> tags = new ArrayList<Tag>();
			tags.add(tag);
			List<PostPO> postPoList = aggregateByType(page, tags,
					PostType.EVALUATION);
			aggregation = new TagAggregation();
			for (PostPO postPO : postPoList) {
				Post p = BeanMapUtils.copy(postPO, 0);
				switch (p.getEnumType()) {
				case EVALUATION:
					aggregation.addEvaluations(p);
					break;
				case INFO:
				default:
					LOG.error("Get wrong type of post.Expected PostType.EVALUATION but others");
					break;
				}
			}
		}
		return aggregation;
	}

	@Override
	@Transactional(readOnly = true)
	public TagAggregation aggregateInfosByTag(Page page, Tag tag) {
		TagAggregation aggregation = null;
		if (tag == null || (StringUtils.isEmpty(tag.getName()) && tag.getId()<=0L)) {
			aggregation = null;
		} else {
			List<Tag> tags = new ArrayList<Tag>();
			tags.add(tag);
			List<PostPO> postPoList = aggregateByType(page, tags, PostType.INFO);
			aggregation = new TagAggregation();
			for (PostPO postPO : postPoList) {
				Post p = BeanMapUtils.copy(postPO, 0);
				switch (p.getEnumType()) {
				case INFO:
					aggregation.addInfos(p);
					break;
				case EVALUATION:
				default:
					LOG.error("Get wrong type of post.Expected PostType.INFO but others");
					break;
				}
			}
		}
		return aggregation;
	}

	@Override
	@Transactional(readOnly = true)
	public TagAggregation aggregateByMultipleTags(Page page, List<Tag> tags) {

		List<PostPO> postPoList = new ArrayList<PostPO>();
		PostType[] postTypes = PostType.values();
		for (PostType postType : postTypes) {
			postPoList.addAll(aggregateByType(page, tags, postType));
		}

		TagAggregation tagAggregation = new TagAggregation();
		for (PostPO postPO : postPoList) {
			Post p = BeanMapUtils.copy(postPO, 0);
			switch (p.getEnumType()) {
			case EVALUATION:
				tagAggregation.addEvaluations(p);
				break;
			case INFO:
				tagAggregation.addInfos(p);
				break;
			default:
				break;
			}
		}
		return tagAggregation;
	}

	private List<PostPO> aggregateByType(Page page, List<Tag> tags,
			PostType postType) {
		List<String> tagNames = new ArrayList<String>();
		for (Tag tag : tags) {
			if(StringUtils.isEmpty(tag.getName())){
				TagPO tagPO=tagDao.get(tag.getId());
				tag.setName(tagPO.getName());
			}
			tagNames.add(tag.getName());
		}
		List<PostPO> postPoList = postDao.findByTags(page, tagNames, postType);
		return postPoList;
	}

	@Override
	@Transactional(readOnly=true)
	public List<Tag> aggregateProductByCategoryTag(Page page, List<Tag> tags) {
		// TODO Auto-generated method stub
		
		//读取tag，剔除非category tag
		List<TagPO> tagPOs=new ArrayList<TagPO>();
		for(Tag tag:tags){
			TagPO tagPO=tagDao.get(tag.getId());
			if(tagPO!=null && tagPO.getEnumType().equals(TagType.CATEGORY)){
				tagPOs.add(tagPO);
			}
		}
		
		//聚合category tag下的product tag（暂不排序）
		List<TagPO> productTagPOs=tagDao.listTagByCategory(page, tagPOs);
		
		List<Tag> ret=new ArrayList<Tag>();
		for(TagPO product:productTagPOs){
			ret.add(BeanMapUtils.copy(product));
		}
		page.setResults(ret);
		return ret;
	}

	@Override
    @Transactional(readOnly = true)
	public TagAggregation aggregateEvulationsByTags(Page page, List<Tag> tags) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
    @Transactional(readOnly = true)
	public TagAggregation aggregateInfosByTags(Page page, List<Tag> tags) {
		// TODO Auto-generated method stub
	    
	    List<PostPO> postPoList = new ArrayList<PostPO>();
	    postPoList = aggregateByType(page, tags, PostType.INFO);

        TagAggregation tagAggregation = new TagAggregation();
        for (PostPO postPO : postPoList) {
            Post p = BeanMapUtils.copy(postPO, 0);
            tagAggregation.addInfos(p);            
        }
        return tagAggregation;
	}

}
